import os
import json
import uuid
import datetime
import shutil
from werkzeug.utils import secure_filename
from flask import current_app
from app.utils.audio import get_audio_duration, is_valid_audio_format
import logging

logger = logging.getLogger(__name__)

class RecordingService:
    """录音服务类，处理录音文件的保存和检索"""
    
    def __init__(self):
        self.temp_folder = os.path.join(current_app.config['UPLOAD_FOLDER'], 'temp')
        self.metadata_folder = current_app.config['METADATA_FOLDER']
        self.upload_folder = current_app.config['UPLOAD_FOLDER']
        
        # 确保所需目录存在
        os.makedirs(self.temp_folder, exist_ok=True)
        os.makedirs(self.metadata_folder, exist_ok=True)
        os.makedirs(self.upload_folder, exist_ok=True)
    
    def save_chunk(self, audio_chunk, session_id, chunk_index, is_final=False):
        """
        保存音频块
        
        Args:
            audio_chunk: 音频块文件
            session_id: 会话ID
            chunk_index: 块索引
            is_final: 是否是最终块
            
        Returns:
            dict: 包含操作结果的字典
        """
        try:
            # 生成临时文件名
            temp_filename = f"temp_chunk_{session_id}_{chunk_index}.wav"
            temp_path = os.path.join(self.temp_folder, temp_filename)
            
            # 保存临时文件
            audio_chunk.save(temp_path)
            
            # 如果是最终块，合并所有音频块
            if is_final:
                return self._merge_chunks(session_id)
            
            return {
                'status': 'success',
                'message': '音频块保存成功',
                'chunk_path': temp_path
            }
            
        except Exception as e:
            logger.error(f"保存音频块失败: {str(e)}")
            return {
                'status': 'error',
                'message': f'保存音频块失败: {str(e)}'
            }
    
    def _merge_chunks(self, session_id):
        """
        合并音频块并保存最终文件
        
        Args:
            session_id: 会话ID
            
        Returns:
            dict: 包含操作结果的字典
        """
        try:
            # 获取所有属于该会话的临时文件
            temp_files = []
            for filename in os.listdir(self.temp_folder):
                if filename.startswith(f"temp_chunk_{session_id}_"):
                    temp_files.append(os.path.join(self.temp_folder, filename))
            
            if not temp_files:
                raise Exception("没有找到需要合并的音频块")
            
            # 按索引排序
            temp_files.sort(key=lambda x: int(x.split('_')[-1].split('.')[0]))
            
            # 生成最终文件名
            final_filename = f"final_{session_id}.wav"
            final_path = os.path.join(self.upload_folder, final_filename)
            
            # 合并音频文件
            with open(final_path, 'wb') as outfile:
                for temp_file in temp_files:
                    with open(temp_file, 'rb') as infile:
                        shutil.copyfileobj(infile, outfile)
            
            # 清理临时文件
            for temp_file in temp_files:
                os.remove(temp_file)
            
            return {
                'status': 'success',
                'message': '音频合并成功',
                'final_path': final_path
            }
            
        except Exception as e:
            logger.error(f"合并音频块失败: {str(e)}")
            return {
                'status': 'error',
                'message': f'合并音频块失败: {str(e)}'
            }
    
    def save_metadata(self, metadata, session_id):
        """
        保存元数据
        
        Args:
            metadata: 元数据字典
            session_id: 会话ID
            
        Returns:
            dict: 包含操作结果的字典
        """
        try:
            # 生成元数据文件名
            metadata_filename = f"metadata_{session_id}.json"
            metadata_path = os.path.join(self.metadata_folder, metadata_filename)
            
            # 添加时间戳
            metadata['uploadTime'] = datetime.datetime.now().isoformat()
            
            # 保存元数据
            with open(metadata_path, 'w', encoding='utf-8') as f:
                json.dump(metadata, f, ensure_ascii=False, indent=2)
            
            return {
                'status': 'success',
                'message': '元数据保存成功',
                'metadata_path': metadata_path
            }
            
        except Exception as e:
            logger.error(f"保存元数据失败: {str(e)}")
            return {
                'status': 'error',
                'message': f'保存元数据失败: {str(e)}'
            }
    
    def cleanup_old_files(self, max_age_hours=24):
        """
        清理旧文件
        
        Args:
            max_age_hours: 文件最大保留时间（小时）
        """
        try:
            current_time = datetime.datetime.now()
            max_age = datetime.timedelta(hours=max_age_hours)
            
            # 清理临时文件夹
            for filename in os.listdir(self.temp_folder):
                file_path = os.path.join(self.temp_folder, filename)
                file_time = datetime.datetime.fromtimestamp(os.path.getmtime(file_path))
                if current_time - file_time > max_age:
                    os.remove(file_path)
                    logger.info(f"已删除过期临时文件: {filename}")
            
            # 清理上传文件夹中的临时文件
            for filename in os.listdir(self.upload_folder):
                if filename.startswith('temp_chunk_'):
                    file_path = os.path.join(self.upload_folder, filename)
                    file_time = datetime.datetime.fromtimestamp(os.path.getmtime(file_path))
                    if current_time - file_time > max_age:
                        os.remove(file_path)
                        logger.info(f"已删除过期临时文件: {filename}")
            
            logger.info("文件清理完成")
            
        except Exception as e:
            logger.error(f"清理文件失败: {str(e)}")
    
    @staticmethod
    def delete_recording(recording_id):
        """
        删除录音
        
        Args:
            recording_id: 录音ID
            
        Returns:
            bool: 是否删除成功
        """
        try:
            metadata_folder = current_app.config['METADATA_FOLDER']
            upload_folder = current_app.config['UPLOAD_FOLDER']
            
            # 删除元数据文件
            metadata_path = os.path.join(metadata_folder, f"metadata_{recording_id}.json")
            if os.path.exists(metadata_path):
                os.remove(metadata_path)
            
            # 删除音频文件
            audio_path = os.path.join(upload_folder, f"final_{recording_id}.wav")
            if os.path.exists(audio_path):
                os.remove(audio_path)
            
            # 删除临时文件
            temp_folder = os.path.join(upload_folder, 'temp')
            for filename in os.listdir(temp_folder):
                if filename.startswith(f"temp_chunk_{recording_id}_"):
                    os.remove(os.path.join(temp_folder, filename))
            
            return True
            
        except Exception as e:
            logger.error(f"删除录音失败: {str(e)}")
            return False

    def save_recording(self, audio_file, word_segments, user_info=None):
        """
        保存录音文件和相关元数据
        
        Args:
            audio_file: 上传的音频文件对象
            word_segments: 单词分段数据列表
            user_info: 用户信息字典，包含IP地址、设备信息等
            
        Returns:
            dict: 包含操作结果的字典
        """
        try:
            logger.info("开始保存录音文件")
            
            # 生成唯一文件名
            original_filename = secure_filename(audio_file.filename)
            file_ext = os.path.splitext(original_filename)[1]
            unique_filename = f"{uuid.uuid4()}{file_ext}"
            
            # 确保上传目录存在
            upload_folder = current_app.config['UPLOAD_FOLDER']
            os.makedirs(upload_folder, exist_ok=True)
            
            # 保存文件
            file_path = os.path.join(upload_folder, unique_filename)
            audio_file.save(file_path)
            
            # 创建元数据文件
            metadata_folder = current_app.config['METADATA_FOLDER']
            os.makedirs(metadata_folder, exist_ok=True)
            
            metadata_filename = f"{os.path.splitext(unique_filename)[0]}.json"
            metadata_path = os.path.join(metadata_folder, metadata_filename)
            
            # 准备元数据 - 符合README格式
            metadata = {
                'wordSegments': word_segments,
                'audioFormat': {
                    'sampleRate': 16000,
                    'bitDepth': 16,
                    'channels': 1
                },
                'filename': unique_filename,
                'uploadTime': datetime.datetime.now().isoformat()
            }
            
            # 添加用户信息到元数据
            if user_info:
                metadata['userInfo'] = user_info
            
            # 保存元数据
            with open(metadata_path, 'w', encoding='utf-8') as f:
                json.dump(metadata, f, ensure_ascii=False, indent=2)
            
            logger.info(f"录音文件保存成功: {unique_filename}")
            
            # 如果是prolific用户，记录到完成名单
            prolific_pid = None
            platform = None
            
            # 从元数据或用户信息中获取平台和用户ID
            # 1. 直接从元数据中获取
            metadata_platform = metadata.get('platform')
            if metadata_platform == 'prolific':
                prolific_pid = metadata.get('prolificPID')
                if prolific_pid:
                    self._record_completion(prolific_pid, metadata_platform)
                    logger.info(f"从元数据中获取到Prolific用户ID: {prolific_pid}")
            
            # 2. 如果元数据中没有，但用户信息中有，也尝试记录
            elif user_info:
                # 检查用户信息中是否有platform字段
                user_platform = user_info.get('platform')
                if user_platform == 'prolific':
                    user_prolific_pid = user_info.get('prolificPID')
                    if user_prolific_pid:
                        self._record_completion(user_prolific_pid, user_platform)
                        logger.info(f"从用户信息中获取到Prolific用户ID: {user_prolific_pid}")
            
            return {
                'status': 'success',
                'message': '录音保存成功',
                'recording': metadata
            }
            
        except Exception as e:
            logger.error(f"保存录音文件失败: {str(e)}")
            return {
                'status': 'error',
                'message': f'保存录音文件失败: {str(e)}'
            }
    
    @staticmethod
    def get_recordings(page=1, per_page=10):
        """
        获取录音列表
        
        Args:
            page: 页码
            per_page: 每页数量
            
        Returns:
            dict: 包含录音列表和分页信息的字典
        """
        metadata_folder = current_app.config['METADATA_FOLDER']
        if not os.path.exists(metadata_folder):
            return {
                'recordings': [],
                'total': 0,
                'page': page,
                'per_page': per_page,
                'pages': 0
            }
        
        # 获取所有元数据文件
        metadata_files = []
        for filename in os.listdir(metadata_folder):
            if filename.endswith('.json'):
                file_path = os.path.join(metadata_folder, filename)
                try:
                    with open(file_path, 'r', encoding='utf-8') as f:
                        metadata = json.load(f)
                        # 确保文件存在
                        if os.path.exists(metadata.get('file_path')):
                            metadata_files.append(metadata)
                except Exception as e:
                    logger.error(f"读取元数据文件失败: {file_path}, 错误: {str(e)}")
        
        # 按创建时间排序
        metadata_files.sort(key=lambda x: x.get('created_at', ''), reverse=True)
        
        # 分页
        total = len(metadata_files)
        start = (page - 1) * per_page
        end = start + per_page
        
        return {
            'recordings': metadata_files[start:end],
            'total': total,
            'page': page,
            'per_page': per_page,
            'pages': (total + per_page - 1) // per_page
        }
    
    @staticmethod
    def get_recording(recording_id):
        """
        获取单个录音信息
        
        Args:
            recording_id: 录音ID
            
        Returns:
            dict: 录音信息
        """
        metadata_folder = current_app.config['METADATA_FOLDER']
        
        # 遍历所有元数据文件查找匹配的ID
        for filename in os.listdir(metadata_folder):
            if filename.endswith('.json'):
                file_path = os.path.join(metadata_folder, filename)
                try:
                    with open(file_path, 'r', encoding='utf-8') as f:
                        metadata = json.load(f)
                        if metadata.get('id') == recording_id:
                            return metadata
                except Exception as e:
                    logger.error(f"读取元数据文件失败: {file_path}, 错误: {str(e)}")
        
        return None
    
    def _record_completion(self, user_id, platform='prolific'):
        """
        记录用户已完成任务
        
        Args:
            user_id: 用户ID（如prolificPID）
            platform: 平台名称
        """
        try:
            # 确保目录存在
            completions_dir = os.path.join('logs/completions')
            os.makedirs(completions_dir, exist_ok=True)
            
            # 读取现有完成记录
            completions_file = os.path.join(completions_dir, 'completions.json')
            completions_data = {}
            
            if os.path.exists(completions_file):
                try:
                    with open(completions_file, 'r') as f:
                        completions_data = json.load(f)
                except Exception as e:
                    logger.error(f"读取完成记录文件出错: {e}")
            
            # 添加新的完成记录
            if user_id not in completions_data:
                completions_data[user_id] = {
                    'completed_at': datetime.datetime.now().isoformat(),
                    'platform': platform
                }
                
                # 保存更新后的记录
                with open(completions_file, 'w') as f:
                    json.dump(completions_data, f, ensure_ascii=False, indent=2)
                
                logger.info(f"用户 {user_id} 的完成记录已保存")
            else:
                logger.info(f"用户 {user_id} 已在完成记录中")
                
        except Exception as e:
            logger.error(f"记录用户完成状态时出错: {e}") 